package code.concurrent;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;

public class NumberPrinter {
    private int maxCount;
    private int number = 1;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition0 = lock.newCondition();
    private final Condition condition1 = lock.newCondition();
    private final Condition condition2 = lock.newCondition();

    public NumberPrinter(int maxCount) {
        this.maxCount = maxCount;
    }

    // 打印3n
    public void print3n(){
        print(()->number % 3==0, condition0, condition1);
    }

    // 打印3n+1
    public void print3nPlus1(){
        print(()->number % 3==1, condition1, condition2);
    }

    // 打印3n
    public void print3nPlus2(){
        print(()->number % 3==2, condition2, condition0);
    }

    private void print(Supplier<Boolean> shouldPrint, Condition cur, Condition next) {
        while (number < maxCount-1){
            try{
                lock.lock();
                while (!shouldPrint.get()) {
                    cur.await();
                }
                System.out.println(Thread.currentThread().getName() + ": " + number++);
                next.signal();
            }catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        NumberPrinter printer = new NumberPrinter(99);
        new Thread(printer::print3n, "Thread A").start();
        new Thread(printer::print3nPlus1, "Thread B").start();
        new Thread(printer::print3nPlus2, "Thread C").start();
    }
}
